public class BHWithFallback {
//    static List<Id> activeBIds = new List<Id>();
    static Id defaultBId = [select Id from businesshours where IsDefault=true].Id;
    
//    BHWithFallback() {
//       for(BusinessHours bh:[select Id,IsDefault from businesshours where IsActive=true Order By IsDefault Desc]) {
//           activeBIds.add(bh.Id);
//       }
//       system.assert( this.defaultBid == activeBIds[0] );
//    }
//    //static BHWithFallback inst = new BHWithFallback();
    
//    public static boolean isActive(Id bid) {
//        if (bid==null) return false;
//        
//        Set<Id> tmpActiveBhIdSet = new Set<Id>();
//        tmpActiveBhIdSet.addAll(inst.activeBIds);
//        return (tmpActiveBhIdSet.contains(bid));
//    } 
    public static Id getSpecifiedOrDefault(Id bId) {
//        //return getSpecifiedOrDefault(bId,null);
//        if (isActive(bId)) return bId;
//        else return inst.defaultBid;
		if (bId==null) return defaultBid;
		else return bId;
    }
// //    public static Id getSpecifiedOrDefault(Id bIdFirstChoice, Id bidSecondChoice) {
// //        if (isActive(bIdFirstChoice)) return bIdFirstChoice;
// //        else if (isActive(bidSecondChoice)) return bidSecondChoice;
// //        else return inst.defaultBid;
// //    }
//    public static Id getDefaultBid() { return defaultBid; }
//    public static Id getAnyBHIdPreferNonDefault() {
//        // activeBIds[0] is the default business hours.  There may or may not be any other elements
//        // in the array.
//        return inst.activeBIds[ inst.activeBIds.size()-1 ];
//    }
    
    public static testMethod void testBHWithFallback_NullBHId() {
//        Id bidNd = BHWithFallback.getAnyBHIdPreferNonDefault();
//        BHWithFallback.getSpecifiedOrDefault(bidNd);
//        system.assert(BHWithFallback.getSpecifiedOrDefault(null) == BHWithFallback.getDefaultBid());
//        BHWithFallback.isActive(bidNd);
//        system.assert(!BHWithFallback.isActive(null));
		Id bid = defaultBId;
		system.assertNotEquals( null, getSpecifiedOrDefault(bid) );
		system.assertNotEquals( null, getSpecifiedOrDefault(null) );
    }
    
    public static testMethod void testBHWithFallback_AddSubtract() {
 //       Id bidNd = BHWithFallback.getAnyBHIdPreferNonDefault();
        //BHWithFallback.getSpecifiedOrDefault(bidNd);
        //system.assert(BHWithFallback.getSpecifiedOrDefault(null) == BHWithFallback.getDefaultBid());
        //BHWithFallback.isActive(bidNd);
        //system.assert(!BHWithFallback.isActive(null));
        
        Id bidNd = defaultBId;
        Datetime dt = system.now();
        Long millis = 1000*60*60;  // 1 hr
        Datetime res = BHWithFallback.BHAdd(bidNd,dt,millis);
        Long backInMillis = BHWithFallback.BHDiff(bidNd,dt,res);
        system.debug('Converted:  with bid='+bidNd);
        system.debug(' > millis='+millis+' PLUS now=' + dt.format('EEE, d MMM yyyy HH:mm:ss Z') + ' -> ');
        system.debug('res=' + res.format('EEE, d MMM yyyy HH:mm:ss Z') );
        system.debug(' -> backToMillis=' + backInMillis );
        Long delta = Math.abs(backInMillis - millis) / 1000L;
        system.debug('delta='+delta);
        system.assert( delta < 61 );
    }
 
    //Returns result in milliseconds
    public static DateTime BHAdd(Id bId, DateTime dt, Long ms){
        return BusinessHours.Add(BHWithFallback.getSpecifiedOrDefault(bId), dt, ms);
    }
    
//    //
//    // addBHours() - adds specified number of business hours using the default business hours id
//    // in this organization
//    // 
//    public static DateTime addBHours(DateTime dt, Decimal hours) {
//        return addBHours(dt, hours, null);
//    }
    
    //Parameters:BusinessHours.Id, DateTime startDate, DateTime endDate
    //Returns result in milliseconds
    public static Long BHDiff(Id bId, DateTime startDate, DateTime endDate){
        return BusinessHours.Diff(BHWithFallback.getSpecifiedOrDefault(bId), startDate, endDate);
    }
    
    static testMethod void testTransition() {
    	Datetime dt = Datetime.newInstance(0);
    	Datetime dt2 = Datetime.newInstance(0).addHours(1);
    	Datetime dt2000 = Datetime.newInstance(0).addDays(2000);
    	Id defBHId = BHWithFallback.getSpecifiedOrDefault(null);
    	system.assertEquals( 
    		BHAdd(defBHId,dt,10*60*60*1000),
    		addBHours(dt,10,defBHId)
    	);
    	system.assertEquals( 
    		Decimal.valueOf( BHDiff(defBHId,dt,dt2) )
    		/ 
    		Decimal.valueOf( 60*60*1000 ),
    		
    		diffBHours(dt,dt2,defBHId)
    	);
    	system.assertEquals( 
    		Decimal.valueOf( BHDiff(defBHId,dt,dt2000) )
    		/ 
    		Decimal.valueOf( 60*60*1000 ),
    		
    		diffBHours(dt,dt2000,defBHId)
    	);    
    }

    //
    // addBHours() - adds specified number of business hours
    //
    public static DateTime addBHours(DateTime dt, Decimal hours, Id bId) {
        Long ms = (hours * 60 * 60 * 1000).longValue();
        return BusinessHours.Add(BHWithFallback.getSpecifiedOrDefault(bId), dt, ms);
    }

    //
    // diffBHours() - diffs two datetimes in business hours
    //
    public static Decimal diffBHours(DateTime dtA, DateTime dtB, Id bId) {
        Long ms = BusinessHours.Diff(
        	BHWithFallback.getSpecifiedOrDefault(bId), dtA, dtB);
    	return Decimal.valueOf( ms / (60*60*1000) );
    }
}